package me.yokeyword.fragmentation;

import me.yokeyword.fragmentation.extensions.FractionEx;
import me.yokeyword.fragmentation.extensions.FractionManagerEx;
import ohos.aafwk.ability.fraction.Fraction;

import java.util.ArrayList;
import java.util.List;

public class SupportHelper {
    private static final long SHOW_SPACE = 200L;

    private SupportHelper() {
    }

    /**
     * 获得栈顶SupportFraction
     * @param fragmentManager Fraction Manager
     * @return get top Fraction from back stack
     */
    public static ISupportFraction getTopFraction(FractionManagerEx fragmentManager) {
        return getTopFraction(fragmentManager, 0);
    }

    public static ISupportFraction getTopFraction(FractionManagerEx fragmentManager, int containerId) {
        List<FractionEx> fragmentList = fragmentManager.getActiveFractions();
        if (fragmentList == null) return null;

        for (int i = fragmentList.size() - 1; i >= 0; i--) {
            FractionEx fraction = fragmentList.get(i);
            if (fraction.getFraction() instanceof ISupportFraction) {
                ISupportFraction iFraction = (ISupportFraction) (fraction.getFraction());
                if (containerId == 0) return iFraction;

                if (containerId == iFraction.getSupportDelegate().mContainerId) {
                    return iFraction;
                }
            }
        }
        return null;
    }

    /**
     * Same as fragmentManager.findFractionByTag(fragmentClass.getName());
     * find Fraction from FractionStack
     * @param fragmentManager Fraction Manager instance
     * @param fragmentClass Fraction class name to find fraction of type class
     * @return found fraction null if not
     */
    @SuppressWarnings("unchecked")
    public static <T extends ISupportFraction> T findFraction(FractionManagerEx fragmentManager, Class<T> fragmentClass) {
        return findStackFraction(fragmentClass, null, fragmentManager);
    }

    /**
     * Same as fragmentManager.findFractionByTag(fragmentTag);
     * <p>
     * find Fraction from FractionStack
     * @param fragmentManager fraction manager
     * @param fragmentTag Fraction tag to find
     * @return found fraction null if not
     */
    @SuppressWarnings("unchecked")
    public static <T extends ISupportFraction> T findFraction(FractionManagerEx fragmentManager, String fragmentTag) {
        return findStackFraction(null, fragmentTag, fragmentManager);
    }

    /**
     * 从栈顶开始，寻找FractionManager以及其所有子栈, 直到找到状态为show & userVisible的Fraction
     * @param fragmentManager  Fraction Manager
     * @return current active fraction
     */
    public static ISupportFraction getActiveFraction(FractionManagerEx fragmentManager) {
        return getActiveFraction(fragmentManager, null);
    }

    @SuppressWarnings("unchecked")
    static <T extends ISupportFraction> T findStackFraction(Class<T> fragmentClass, String toFractionTag, FractionManagerEx fragmentManager) {
        Fraction fraction = null;
        if (toFractionTag == null) {
            List<FractionEx> fragmentList = fragmentManager.getActiveFractions();
            if (fragmentList == null) return null;

            int sizeChildFrgList = fragmentList.size();
            for (int i = sizeChildFrgList - 1; i >= 0; i--) {
                Fraction brotherFraction = fragmentList.get(i).getFraction();
                if (brotherFraction instanceof ISupportFraction && brotherFraction.getClass().getName().equals(fragmentClass.getName())) {
                    fraction = brotherFraction;
                    break;
                }
            }
        } else {
            fraction = fragmentManager.getFractionExByTag​(toFractionTag).getFraction();
            if (fraction == null) return null;
        }
        if (fraction != null)
            return (T) fraction;
        else
            return null;
    }

    private static ISupportFraction getActiveFraction(FractionManagerEx fragmentManager, ISupportFraction parentFraction) {
        List<FractionEx> fragmentList = fragmentManager.getActiveFractions();
        if (fragmentList == null) {
            return parentFraction;
        }
        for (int i = fragmentList.size() - 1; i >= 0; i--) {
            Fraction fraction = fragmentList.get(i).getFraction();
            if (fraction instanceof ISupportFraction) {
                return (ISupportFraction) fraction;
            }
        }
        return parentFraction;
    }

    /**
     * Get the topFraction from BackStack
     * @param fragmentManager Fraction Manager instance
     * @return get Top Fraction in backstack
     */
    public static ISupportFraction getBackStackTopFraction(FractionManagerEx fragmentManager) {
        return getBackStackTopFraction(fragmentManager, 0);
    }

    public static FractionEx getBackStackTopFractionEx(FractionManagerEx fragmentManager) {
        return getBackStackTopFractionEx(fragmentManager, 0);
    }
    /**
     * Get the topFraction from BackStack
     * @param fragmentManager Fraction manager
     * @param containerId Resource id to place fraction
     * @return top fraction from backstack
     */
    public static FractionEx getBackStackTopFractionEx(FractionManagerEx fragmentManager, int containerId) {
        long count = fragmentManager.getBackStackEntryCount();
        for (int i = (int) (count - 1); i >= 0; i--) {
            FractionEx fractionex = fragmentManager.getBackStackEntryAt(i);
            if (!fractionex.getActive())
                continue;
            Fraction fraction = fractionex.getFraction();
            if (fraction instanceof ISupportFraction) {
                if (containerId == 0) return fractionex;
                if (containerId == ((ISupportFraction)(fractionex.getFraction())).getSupportDelegate().mContainerId) {
                    return fractionex;
                }
            }
        }
        return null;
    }

    public static ISupportFraction getBackStackTopFraction(FractionManagerEx fragmentManager, int containerId) {
        FractionEx fex = getBackStackTopFractionEx(fragmentManager,containerId);
        if (fex != null)
            return (ISupportFraction)fex.getFraction();
        else
            return null;
    }

    @SuppressWarnings("unchecked")
    static <T extends ISupportFraction> T findBackStackFraction(Class<T> fragmentClass, String toFractionTag, FractionManagerEx fragmentManager) {
        int count = (int) fragmentManager.getBackStackEntryCount();

        if (toFractionTag == null) {
            toFractionTag = fragmentClass.getName();
        }

        for (int i = count - 1; i >= 0; i--) {
            FractionEx entry = fragmentManager.getBackStackEntryAt(i);
            if (toFractionTag.equals(entry.getTag())) {
                FractionEx fraction = fragmentManager.findFractionByTag(entry.getTag());
                if (fraction.getFraction() instanceof ISupportFraction) {
                    return (T) fraction.getFraction();
                }
            }
        }
        return null;
    }

    static List<Fraction> getWillPopFractions(FractionManagerEx fm, String targetTag, boolean includeTarget) {
        FractionEx target = fm.findFractionByTag(targetTag);
        List<Fraction> willPopFractions = new ArrayList<>();

        List<FractionEx> fragmentList = fm.getActiveFractions();
        if (fragmentList == null) return willPopFractions;

        int size = fragmentList.size();

        int startIndex = -1;
        for (int i = size - 1; i >= 0; i--) {
            if (target == fragmentList.get(i)) {
                if (includeTarget) {
                    startIndex = i;
                } else if (i + 1 < size) {
                    startIndex = i + 1;
                }
                break;
            }
        }

        if (startIndex == -1) return willPopFractions;

        for (int i = size - 1; i >= startIndex; i--) {
            FractionEx fraction = fragmentList.get(i);
            if (fraction != null && fraction.getFraction().getComponent() != null) {
                willPopFractions.add(fraction.getFraction());
            }
        }
        return willPopFractions;
    }
}
